package main.test.SparkAPI.Baics.singletonObj

object testSingObj {
  /**
   * Implement a singleton object
   * Use objects as executable programs
   * Define static functions in a companion object
   * Create factory methods using the apply function.
   * The essence of object-oriented programing is representing
   * elements of the real world
   * using classes that describe their behavior through methods.In
   * specific scenarios, such as configurations and main entry points, you
   * need to instantiate a coding element at most once; you usually call it
   * singleton.In scala,
   * you can create singletons using objects
   * elegantly and concisely. You are also encouraged to
   * clearly distinguish between static and non-static methods;
   * the non-static ones act on a specific instance of a class, while the
   * static ones belong to its general definition.
   * In scala, you implement non-static methods in a class and static methods in an object.In the
   * capstone, you'll use an object ot define the main entry point of your application.
   */


  /**
   * Consider:
   * Can you think of a few possible use cases for singletons? What about static methods for a class?
   * Can you think of a few examples?
   */
    // Object
    def testObject()= {
      /**
       * consider the folling class to represent a robot
       * The function welcome is abstract , it takes no praras,and
       * it returns  a value fo type String.
       * Suppose you want to represent a vocabulary of sentences that a
       * robot can use when asked to speak.This vocabulary must be autonomous from
       * any particular implementation of a robot; it must be unique in the whole application and
       * shared between multiple sources.
       *
       * When using the object Vocabulary, you refer to it by name.
       * Note that you do not use the keyword new because you cannot request to
       * instantiate an object explicitly.The compiler guarantees that hte JVM instantiates an object no more than once;
       * in other words, it treats it as a singleton.The first time you request access to an object,
       * the JVM allocates it in memory; following references to the same object
       * do not trigger any new instantiation because the JVM reuses its first memory allocation,
       * a model called singleton pattern.
       */

      /**
       * Think in scala the term object
       * Many object-oriented languages uses the word object to indicate an instance
       * of a class. A few examples are Java, Python,JavaScript and C++.
       * In scala, object has well-defined and specific meaning:it refers
       * to a singleton, not an instance of a class. When referring to scala
       * code, make sure to use the term object correctly to avoid confusion!
       */

      /**
       * The use of singletons is not unique to scala.Still, its implementation is extremely elegant
       * and convenient to use compared to other languages.
       */

      /**
       * Sigleton in different languase
       * {{
       *
       * //java
       * public class MySingleton {
       *    private static MySingleton instance = null;
       *    private MySingleton() {}
       *    public static MySingleton getInstance() {
       *    if (instance == null) {
       *        instance = new ClassicSingleton();
       *        }
       *        return instance;
       *    }
       *
       *
       * }
       * }}
       *
       *
       * {{
       * // Scala -> only 2 words
       * object MySingleton
       * }}
       */
    }


  abstract  class Robt(name:String) {
    def welcome:String
  }


  // Executable object

  /***
   * A program usually has at least one entry point to start its execution;
   * you can refer to this as main or executable. Note that a main for a program is
   * a singleton: you cannot have more than one instance of the same main when running
   * a program.
   * In scala, your program's entry point is an object with a main
   * function; this behavior is consistent across the JVM languages
   * Below demonstrates how to create an executable object that prints the text "Hello world"
   * in the console.
   *
   */


    // The apply method

  /**
   * In section 7. you learned that a class can have one constructor,
   * and you can use it by using the keyword new.
   * What if you want to specify different ways of creating a class?
   * How can you do it with only on construcotr?
   * The apply function of a companion object can help in solving your problem.
   * Assume you have a Person class and that you can create an intance ofr it by
   * calling the constructor using the keyword new and profiding its
   * parameters. You'd also like to define an alternative way of creating a
   * person by merging two exising ones.
   *
   */
  def main(args: Array[String]): Unit = {
    println(Vocabulary.sentenceA)
    println(Vocabulary.sentenceB)


      println("Hello world!")
      /**
       * a companion object is an object that has the same name as another existing class.
       * Consider about the Robot class you saw before in section11.1
       * and suppose you want to  define a function to return the most talktive robot.
       *
       * An example usage for mostTalkative and the object Vocabulary implemented in below:
       *
       */
      val tom = new Robot("Tom") {
        override def welcome: String = Vocabulary.sentenceA
      }
      val alice = new Robot("Alice") {
        override def welcome: String = Vocabulary.sentenceB
      }

    val robot = Robot.mostTalkative(tom, alice)
    println(robot.welcome)
    println(robot.myname)

    val toms = new Person("Tom", 24)
    val alices = new Person("Alice", 23)
//    alices.name

    val P1: Person = Person.apply(toms, alices)
    val P2 = Person(toms, alices)
    println(s"Person ${P1.name} is ${P1.age} year"+ {if (P1.age>1) "s" else ""} + " old.")

    /**
     * The unapply method : A quick preview
     * You have discovered that the apply method is a static method function
     * to construct class instances. The method unapply method is complementary to it;
     * it deconstructs a class into its parameters.
     * unapply is a static function that lives in a class's companion object;
     * it takes an instance class and returns its decomposed representaton.
     * For example, you could ientify a Person class by providing a pair with its name and age.
     * THe unapply function allows you to use pattern matching, a powerful and expressive tool of the Scalal toolbox to match
     * conditions (e.g. age greater than 18)
     * based on the decomposition of a class. You'll learn more about this in the
     * next unit.
     * Learn unapply method later in the book when discussing case class and the type Tuple in lesson 25.
     */
    /**
     * From scala3, the compiler automatically generates an apply
     * fucntion for all your calssese;
     * you can omit the new keyword even if you haven't manually defned an apply method for it
     *
     */





  }
}
